﻿
using EmperialApps.WeatherSpark.Data;
using EmperialApps.WeatherSpark.Internal;
using EmperialApps.WeatherSpark.Resources;
using Microsoft.Phone.Controls;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using System.Windows.Threading;

namespace EmperialApps.WeatherSpark {

    /// <summary>Displays forecast settings.</summary>
    public partial class SettingsPage : PhoneApplicationPage {

        private readonly DispatcherTimer _tileUpdateDelay;

        private Coordinate _location;
        private string _description;


        public SettingsPage( ) {
            typeof( SettingsPage ).Log( "Initializing" );
            InitializeComponent( );

            this._tileUpdateDelay = new DispatcherTimer { Interval = TimeSpan.FromSeconds( 4 ) };
            this._tileUpdateDelay.Tick += this.OnTileUpdateDelayTick;

            if( Settings.Current != null ) {
                typeof( SettingsPage ).Log( "- Reading settings for forecast " + Settings.Current.GetIndex( ) );
                this.InitializeWithCurrentSettings( );
            }
        }


        protected override void OnNavigatedTo( NavigationEventArgs e ) {
            base.OnNavigatedTo( e );

            if( this.EnsureCurrentSettings( fallback: true ) || this.TileFront.SelectedIndex != (int)Settings.Current.Tile )
                this.InitializeWithCurrentSettings( );

            LocationSettings settings = Settings.Current;
            ForecastSource source = settings.Source;

            this.ForecastSource.Text = AppResources.ResourceManager.GetString( "SettingsPage_Source_" + source.Id );

            this.LinkContainer.Children.Clear( );
            foreach( var item in source.GetPageUrls( settings.Location, settings.Units, settings.DownloadUri ) ) {
                string content = AppResources.ResourceManager.GetString( "SettingsPage_Source_" + item.Item1 + "Link" );
                var hyperlink = new HyperlinkButton { Content = content, NavigateUri = item.Item2 };
                this.LinkContainer.Children.Add( hyperlink );
            }

            this.TileTitle.Text = settings.GetDisplayName( );

            Forecast forecast;
            Exception error;
            if( settings.Location.TryLoadForecast( typeof( SettingsPage ), settings.GetIndex( ), out forecast, out error ) )
                this.DisplayForecast( forecast );
            else if( error != null )
                error.Report( Localized.ErrorSource.Loading );

            foreach( var list in new[] { this.TileFront, this.TileBack } )
                foreach( TileOption tile in list.Items )
                    tile.RefreshBackgroundColor( );
        }

        protected override void OnNavigatedFrom( NavigationEventArgs e ) {
            typeof( SummaryPage ).Log( "Leaving" );
            base.OnNavigatedFrom( e );

            // Perform any delayed tile update.
            if( this._tileUpdateDelay.IsEnabled )
                this.DoDelayedSettingChangeTileUpdate( );
        }


        private void InitializeWithCurrentSettings( ) {
            LocationSettings settings = Settings.Current;
            if( settings.Tile != ForecastDisplayMode.None )
                settings.UpdateTile( this.TileProgress, TileUpdateReason.Refresh );

            this.TileFront.SelectedIndex = (int)settings.Tile;
            this.UpdateTileBackSelector( settings.Tile );

            if( settings.Units == Units.Metric )
                this.MetricUnitsButton.IsChecked = true;
            else
                this.ImperialUnitsButton.IsChecked = true;

            this.SummaryPageGraph.Units = settings.Units;
            this.DetailPageGraph.Units = settings.Units;

            this.ShowNightExtremesButton.IsChecked = settings.NightExtremes;

            this.SummaryPageSelector.DisplayLevelChanged -= this.OnSummaryDisplayLevelChanged;
            this.DetailPageSelector.DisplayLevelChanged -= this.OnDetailDisplayLevelChanged;
            {
                ForecastDisplayLevel supportedMask = settings.Source.SupportedDisplayLevel;
                ForecastDisplayLevel detailDisplayLevel = settings.GetDetailPageLevel( );
                ForecastDisplayLevel summaryDisplayLevel = settings.GetSummaryPageLevel( );
                this.DetailPageSelector.SetDisplayLevel( detailDisplayLevel, supportedMask, ForecastDisplayLevel.DetailsMask );
                this.SummaryPageSelector.SetDisplayLevel( summaryDisplayLevel, supportedMask, ForecastDisplayLevel.SummaryMask );
            }
            this.SummaryPageSelector.DisplayLevelChanged += this.OnSummaryDisplayLevelChanged;
            this.DetailPageSelector.DisplayLevelChanged += this.OnDetailDisplayLevelChanged;
        }

        private void UpdateTileBackSelector( ForecastDisplayMode displayMode ) {
            this.TileBack.SelectionChanged -= this.OnTileBackSelectionChanged;
            {
                this.TileBack.Items.Clear( );
                if( displayMode == ForecastDisplayMode.None ) {
                    this.TileLabelRow.Height = new GridLength( 0 );
                    this.TileBack.Visibility = Visibility.Collapsed;
                    this.AdvancedTileSettingsButton.Visibility = Visibility.Collapsed;
                }
                else {
                    this.TileLabelRow.Height = GridLength.Auto;
                    this.TileBack.Visibility = Visibility.Visible;
                    this.AdvancedTileSettingsButton.Visibility = Visibility.Visible;

                    var tile = (TileOption)this.TileFront.Items[1];
                    this.TileBack.Items.Add( new TileOption { Forecast = tile.Forecast, DisplayMode = ForecastDisplayMode.None } );
                    this.TileBack.Items.Add( new TileOption { Forecast = tile.Forecast, DisplayMode = displayMode } );
                    this.TileBack.SelectedIndex = Settings.Current.DisableTileFlip ? 0 : 1;
                }
            }
            this.TileBack.SelectionChanged += this.OnTileBackSelectionChanged;
        }

        private void DisplayForecast( Forecast forecast ) {
            this._location = forecast.Location;
            this._description = forecast.Description;
            this.DisplayForecastLocation( );

            foreach( TileOption tile in this.TileFront.Items ) {
                if( tile.DisplayMode != ForecastDisplayMode.None )
                    tile.Forecast = forecast;
            }

            foreach( TileOption tile in this.TileBack.Items ) {
                if( tile.DisplayMode != ForecastDisplayMode.None )
                    tile.Forecast = forecast;
            }

            int offset = (int)forecast.Start.HoursFrom( forecast.Start.GetDateOffset( ) );
            Forecast graphForecast =
                offset < forecast.Interval
                    ? forecast
                    : Forecast.Combine( forecast, forecast, forecast.Interval * forecast.Temperature.Count - ConvertValue.HoursPerDay + offset );
            this.SummaryPageGraph.Forecast = Forecast.Trim( graphForecast, ConvertValue.HoursPerDay * 3 );
            this.DetailPageGraph.Forecast = Forecast.Trim( graphForecast, ConvertValue.HoursPerDay + forecast.Interval + 1 );
            this.DetailPageGraph.FollowingReferenceLine = true;
        }

        private void DisplayForecastLocation( ) {
            var place = Place.Create( Settings.Current.Units, this._location, this._description );
            this.ForecastDescription.Text = place.Name;

            this.ForecastLocation.Text = place.Location.GetGeographicName( );
        }


        private void DoTileUpdate( TileUpdateReason reason ) {
            this._tileUpdateDelay.Stop( );

            Settings.Current.UpdateTile( this.TileProgress, reason );
        }

        private void DoDelayedSettingChangeTileUpdate( ) {
            this.DoTileUpdate( TileUpdateReason.SettingChange );
        }

        private void DelaySettingChangeTileUpdate( ) {
            if( this._tileUpdateDelay.IsEnabled )
                this._tileUpdateDelay.Stop( );

            this._tileUpdateDelay.Start( );
        }

        private void OnTileUpdateDelayTick( object sender, EventArgs e ) {
            this.DoDelayedSettingChangeTileUpdate( );
        }


        private void OnLocationButtonClicked( object sender, RoutedEventArgs e ) {
            Uri address = Settings.ChooseLocationPage.GetIndexedPageAddress( Settings.Current.GetIndex( ) );
            this.NavigationService.Navigate( address );
        }

        private void OnTileSelectionChanged( object sender, SelectionChangedEventArgs e ) {
            if( this.TileFront == null )
                return;

            var tile = (TileOption)this.TileFront.SelectedItem;

            if( Settings.Current.Tile != tile.DisplayMode ) {
                Settings.Current.Tile = tile.DisplayMode;
                this.DoTileUpdate( TileUpdateReason.CreateTile );
                this.UpdateTileBackSelector( tile.DisplayMode );
            }
        }

        private void OnTileBackSelectionChanged( object sender, SelectionChangedEventArgs e ) {
            if( this.TileBack == null || this.TileBack.SelectedItem == null )
                return;

            var tile = (TileOption)this.TileBack.SelectedItem;
            bool disableFlip = tile.DisplayMode == ForecastDisplayMode.None;

            if( Settings.Current.DisableTileFlip != disableFlip ) {
                Settings.Current.DisableTileFlip = disableFlip;
                this.DelaySettingChangeTileUpdate( );
            }
        }

        private void OnTileTitleChanged( object sender, TextChangedEventArgs e ) {
            string text = this.TileTitle.Text;
            if( string.IsNullOrWhiteSpace( text ) || text == Settings.Current.Search )
                text = null;

            if( Settings.Current.TileTitle == text )
                return;

            Settings.Current.TileTitle = text;
            this.DelaySettingChangeTileUpdate( );
        }

        private void OnUnitButtonClicked( object sender, RoutedEventArgs e ) {
            Units units =
                this.MetricUnitsButton.IsChecked == true
                    ? Units.Metric
                    : Units.Imperial;

            Settings.Current.Units = units;
            this.DisplayForecastLocation( );
            this.SummaryPageGraph.Units = units;
            this.DetailPageGraph.Units = units;
            this.DelaySettingChangeTileUpdate( );
        }

        private void OnAdvancedTileSettingsButtonClicked( object sender, RoutedEventArgs e ) {
            this.NavigationService.Navigate( Settings.AdvancedSettingsPage );
        }

        private void OnShowNightExtremesButtonClicked( object sender, RoutedEventArgs e ) {
            bool nightExtremes = this.ShowNightExtremesButton.IsChecked == true;
            Settings.Current.NightExtremes = nightExtremes;
        }

        private void OnSummaryDisplayLevelChanged( object sender, RoutedPropertyChangedEventArgs<ForecastDisplayLevel> e ) {
            ForecastDisplayLevel summaryLevel = e.NewValue | ForecastDisplayLevel.TemperatureMask | ForecastDisplayLevel.Set;
            Settings.Current.SummaryPageLevel = summaryLevel;
        }

        private void OnDetailDisplayLevelChanged( object sender, RoutedPropertyChangedEventArgs<ForecastDisplayLevel> e ) {
            ForecastDisplayLevel detailLevel = e.NewValue | ForecastDisplayLevel.TemperatureMask | ForecastDisplayLevel.Set;
            Settings.Current.DetailPageLevel = detailLevel;
        }

    }

}
